package dice.sinanya.dice.roll;

import dice.sinanya.dice.MakeNickToSender;
import dice.sinanya.entity.EntityStrManyRolls;
import dice.sinanya.entity.EntityTypeMessages;
import dice.sinanya.exceptions.*;
import dice.sinanya.tools.makedata.Calculator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static dice.sinanya.system.MessagesInit.INIT_LIST;
import static dice.sinanya.system.MessagesRollMaxValue.ROLL_MAX_VALUE;
import static dice.sinanya.system.MessagesSystem.NONE;
import static dice.sinanya.system.MessagesSystem.SPACE;
import static dice.sinanya.system.MessagesTag.*;
import static dice.sinanya.tools.checkdata.CheckCantInPrivate.checkCantInPrivate;
import static dice.sinanya.tools.checkdata.CheckIsNumbers.isNumeric;
import static dice.sinanya.tools.getinfo.GetMessagesProperties.entitySystemProperties;
import static dice.sinanya.tools.getinfo.GetNickName.getNickName;
import static dice.sinanya.tools.makedata.GetRollResultAndStr.getResFunctionAndResultInt;
import static dice.sinanya.tools.makedata.MakeMessages.deleteTag;
import static dice.sinanya.tools.makedata.RandomInt.random;
import static dice.sinanya.tools.makedata.Sender.sender;
import static dice.sinanya.tools.makedata.StringFormatById.stringFormatById;
import static java.lang.Math.ceil;

/**
 * @author SitaNya
 * 日期: 2019-06-15
 * 电子邮箱: sitanya@qq.com
 * 维护群(QQ): 162279609
 * 有任何问题欢迎咨询
 * 类说明: DND先攻骰掷及列表
 */
public class RiAndInit implements MakeNickToSender {
    private static final Logger logger = LogManager.getLogger(MakeNickToSender.class.getName());
    private static final Pattern getName = Pattern.compile("\\[(.*)]");
    private static final Pattern numAndName = Pattern.compile(".*?([+*/\\-dkq \\d]+)([^\\d+*\\-/dkq].+)");
    private static final Pattern plus = Pattern.compile("([+*/\\-][\\d(])");
    private final Pattern getParam = Pattern.compile("(\\d+)*(d\\d+)*(k\\d+)*(q\\d+)*");

    private final Pattern nickNameRegex = Pattern.compile("([\\u4e00-\\u9fa5]+)");

    private final EntityTypeMessages entityTypeMessages;

    public RiAndInit(EntityTypeMessages entityTypeMessages) {
        this.entityTypeMessages = entityTypeMessages;
    }

    /**
     * 根据value从大到小排序先攻列表
     *
     * @param map 先攻列表，key为骰点人+骰点过程，value为骰点结果
     * @return 排序后的map
     */
    public static HashMap<String, String> sortHashMap(HashMap<String, String> map) {
        //從HashMap中恢復entry集合，得到全部的鍵值對集合
        Set<Map.Entry<String, String>> entey = map.entrySet();
        //將Set集合轉為List集合，為了實用工具類的排序方法
        List<Map.Entry<String, String>> list = new ArrayList<>(entey);
        //使用Collections工具類對list進行排序
        list.sort((o1, o2) -> {
            //按照age倒敘排列
            String[] o1Value = o1.getValue().split("=");
            String[] o2Value = o2.getValue().split("=");
            String tmp = o2Value[o2Value.length - 1].trim();
            String tmp2 = o1Value[o1Value.length - 1].trim();
            return Integer.parseInt(o2Value[o2Value.length - 1].trim()) - Integer.parseInt(o1Value[o1Value.length - 1].trim());
        });
        //創建一個HashMap的子類LinkedHashMap集合
        LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>();
        //將list中的數據存入LinkedHashMap中
        for (Map.Entry<String, String> entry : list) {
            linkedHashMap.put(entry.getKey(), entry.getValue());
        }
        return linkedHashMap;
    }

    /**
     * 根据value从大到小排序先攻列表
     *
     * @param map 先攻列表，key为骰点人+骰点过程，value为骰点结果
     * @return 排序后的map
     */
    public static HashMap<String, Integer> sortHashMapByKey(HashMap<String, Integer> map) {
        //從HashMap中恢復entry集合，得到全部的鍵值對集合
        Set<Map.Entry<String, Integer>> entey = map.entrySet();
        //將Set集合轉為List集合，為了實用工具類的排序方法
        List<Map.Entry<String, Integer>> list = new ArrayList<>(entey);
        //使用Collections工具類對list進行排序
        list.sort((o1, o2) -> {
            //按照age倒敘排列
            int o1Value = o1.getValue();
            int o2Value = o2.getValue();
            return o2Value - o1Value;
        });
        //創建一個HashMap的子類LinkedHashMap集合
        LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>();
        //將list中的數據存入LinkedHashMap中
        for (Map.Entry<String, Integer> entry : list) {
            linkedHashMap.put(entry.getKey(), entry.getValue());
        }
        return linkedHashMap;
    }

    /**
     * 根据value从大到小排序先攻列表
     *
     * @param map 先攻列表，key为骰点人+骰点过程，value为骰点结果
     * @return 排序后的map
     */
    public static HashMap<Long, Long> sortHashMapLongByKey(HashMap<Long, Long> map) {
        //從HashMap中恢復entry集合，得到全部的鍵值對集合
        Set<Map.Entry<Long, Long>> entey = map.entrySet();
        //將Set集合轉為List集合，為了實用工具類的排序方法
        List<Map.Entry<Long, Long>> list = new ArrayList<>(entey);
        //使用Collections工具類對list進行排序
        list.sort((o1, o2) -> {
            //按照age倒敘排列
            long o1Value = o1.getKey();
            long o2Value = o2.getKey();
            return Math.toIntExact(o2Value - o1Value);
        });
        //創建一個HashMap的子類LinkedHashMap集合
        LinkedHashMap<Long, Long> linkedHashMap = new LinkedHashMap<>();
        //將list中的數據存入LinkedHashMap中
        for (Map.Entry<Long, Long> entry : list) {
            linkedHashMap.put(entry.getKey(), entry.getValue());
        }
        return linkedHashMap;
    }

    /**
     * 先攻骰掷，这里支持加值和减值计算，并且如果信息中包含汉字，则和对方昵称放在一起（通常kp使用）
     * 返回结果后还会把结果插入先攻列表记录，用于打印先攻列表
     */
    public void ri() throws CantInPrivateException, ManyRollsTimesTooMoreException, RollCantInZeroException, CantDndUseKAndQException {
        checkCantInPrivate(entityTypeMessages);
        String tag = TAG_RI;
        StringBuilder msg = new StringBuilder(deleteTag(entityTypeMessages.getMsgGet().getMsg(), tag.substring(0, tag.length() - 2)));
        String msgBefore = msg.toString();
        int result = 0;
        boolean kEnable = false;
        boolean qEnable = false;
        int maxRoll=ROLL_MAX_VALUE.getOrDefault(entityTypeMessages.getFromGroupString(), 20);
        int random = random(1,maxRoll , entityTypeMessages);
        String nick = getNickName(entityTypeMessages);

        Matcher mNumAndName = numAndName.matcher(msg.toString());
        while (mNumAndName.find()) {
            msg = new StringBuilder(mNumAndName.group(1));
            nick = mNumAndName.group(2).trim() + "(" + getNickName(entityTypeMessages) + ")";
        }
        msg = new StringBuilder(msg.toString().trim());

        Matcher mParams = getParam.matcher(msg.toString());
        while (mParams.find()) {
            String times = mParams.group(1);
            String max = mParams.group(2);
            String k = mParams.group(3);
            String q = mParams.group(4);
            if (k != null && q != null) {
                throw new CantDndUseKAndQException(entityTypeMessages);
            }
            if (k == null) {
                k = "";
            } else {
                kEnable = true;
            }
            if (q == null) {
                q = "";
            } else {
                qEnable = true;
            }
            String function = times + max + k + q;
            String[] tmp = new String[]{function};
            EntityStrManyRolls entityStrManyRolls = getResFunctionAndResultInt(entityTypeMessages, function, tmp);
            msg = new StringBuilder(msg.toString().replaceFirst(function, entityStrManyRolls.getStrResult()));
        }
        if (kEnable || qEnable) {
            random = 0;
        }
        if (!msg.toString().equals("") && msg.charAt(0) != '+' && msg.charAt(0) != '-') {
            msg.insert(0, "+");
        }
        Matcher mPlus = plus.matcher(msg.toString());
        while (mPlus.find()) {
            result = (int) ceil(Calculator.conversion(random + msg.toString().replaceAll("\\[.*?]", "")));
        }


        if (!msg.toString().contains("-") && !msg.toString().equals(NONE) && msg.toString().matches("\\d+")) {
            result = random + Integer.parseInt(msg.toString());
        }

        String msgRemoveFunction = msg.toString().replace("+", "").replace("-", "");
        Matcher mNickNameRegex = nickNameRegex.matcher(msgRemoveFunction);
        if (result == 0) {
            result = random;
            if (mNickNameRegex.find()) {
                nick = msgRemoveFunction;
                msg = new StringBuilder(NONE);
            } else {
                nick = getNickName(entityTypeMessages);
            }
        }

        nick = makeNickToSender(nick);
        String tagInitText = entitySystemProperties.getRiStr(entityTypeMessages.getFromGroupString()) + ": D"+maxRoll+"=\t";
        if (msg.toString().equals(NONE)) {
            nick = nick + "(" + getNickName(entityTypeMessages) + ")";
            sender(entityTypeMessages, nick + tagInitText + result);
            msgBefore = msg.toString() + "=";
        } else {
            if (kEnable) {
                tagInitText = entitySystemProperties.getRiStr(entityTypeMessages.getFromGroupString()) + msgBefore + " =";
            } else if (qEnable) {
                tagInitText = entitySystemProperties.getRiStr(entityTypeMessages.getFromGroupString()) + msgBefore + " =";
            }
            if (kEnable || qEnable) {
                sender(entityTypeMessages, nick + tagInitText + msg.substring(1, msg.length()) + "=" + result);
                msgBefore = msg.toString() + "=";
            } else {
                sender(entityTypeMessages, nick + tagInitText + random + msg + "=" + result);
                msgBefore = random + msg.toString() + "=";
            }
        }
        if (INIT_LIST.containsKey(entityTypeMessages.getFromGroupString())) {
            HashMap<String, String> sort = sortHashMap(INIT_LIST.get(entityTypeMessages.getFromGroupString()));
            for (Map.Entry<String, String> mapEntry2 : sort.entrySet()) {
                Matcher matcher = getName.matcher(mapEntry2.getKey());
                if (matcher.find() && matcher.group(1).equals(nick)) {
                    INIT_LIST.get(entityTypeMessages.getFromGroupString()).remove(mapEntry2.getKey());
                }
            }
        }
        Matcher mMsgBefore = nickNameRegex.matcher(msgBefore);
        if (INIT_LIST.containsKey(entityTypeMessages.getFromGroupString())) {
            Map<String, String> riList = INIT_LIST.get(entityTypeMessages.getFromGroupString());
            INIT_LIST.put(entityTypeMessages.getFromGroupString(), (HashMap<String, String>) putInitList(nick, riList, mMsgBefore, msgBefore, result));
        } else {
            Map<String, String> riList = new HashMap<>(30);
            INIT_LIST.put(entityTypeMessages.getFromGroupString(), (HashMap<String, String>) putInitList(nick, riList, mMsgBefore, msgBefore, result));
        }
    }

    /**
     * 打印先攻列表，根据群号确定列表后，根据骰点最终结果排序后顺序打印
     */
    public void init() throws CantInPrivateException {
        checkCantInPrivate(entityTypeMessages);
        StringBuilder stringBuffer = new StringBuilder();
        if (!INIT_LIST.containsKey(entityTypeMessages.getFromGroupString())) {
            sender(entityTypeMessages, entitySystemProperties.getDndInitIsEmtpy(entityTypeMessages.getFromGroupString()));
            return;
        }
        stringBuffer.append(entitySystemProperties.getInitStr(entityTypeMessages.getFromGroupString()) + ":\n");
        int i = 1;
        if (INIT_LIST.containsKey(entityTypeMessages.getFromGroupString())) {
            HashMap<String, String> sort = sortHashMap(INIT_LIST.get(entityTypeMessages.getFromGroupString()));
            for (Map.Entry<String, String> mapEntry2 : sort.entrySet()) {
                stringBuffer.append(i)
                        .append(".\t")
                        .append(mapEntry2.getKey())
                        .append(mapEntry2.getValue())
                        .append("\n");
                i++;
            }
        }

        sender(entityTypeMessages, stringBuffer.substring(0, stringBuffer.length() - 1));
    }

    /**
     * 打印先攻列表，根据群号确定列表后，根据骰点最终结果排序后顺序打印
     */
    public void rm() throws CantInPrivateException {
        checkCantInPrivate(entityTypeMessages);
        String tag = TAG_INIT_RM;
        String msg = deleteTag(entityTypeMessages.getMsgGet().getMsg(), tag.substring(0, tag.length() - 2));
        StringBuilder stringBuffer = new StringBuilder();
        if (!INIT_LIST.containsKey(entityTypeMessages.getFromGroupString())) {
            sender(entityTypeMessages, entitySystemProperties.getDndInitIsEmtpy(entityTypeMessages.getFromGroupString()));
            return;
        }
        stringBuffer.append(entitySystemProperties.getInitRm(entityTypeMessages.getFromGroupString())).append(":\n");
        int i = 1;
        if (INIT_LIST.containsKey(entityTypeMessages.getFromGroupString())) {
            HashMap<String, String> sort = sortHashMap(INIT_LIST.get(entityTypeMessages.getFromGroupString()));
            for (Map.Entry<String, String> mapEntry2 : sort.entrySet()) {
                Matcher matcher = getName.matcher(mapEntry2.getKey());
                if (matcher.find() && matcher.group(1).toLowerCase().equals(msg)) {
                    stringBuffer.append(i).append(".\t").append(mapEntry2.getKey()).append(mapEntry2.getValue());
                    INIT_LIST.get(entityTypeMessages.getFromGroupString()).remove(mapEntry2.getKey());
                }
                i++;
            }
        }

        sender(entityTypeMessages, stringBuffer.toString());
    }

    /**
     * 打印先攻列表，根据群号确定列表后，根据骰点最终结果排序后顺序打印
     */
    public void set() throws CantInPrivateException, InitSetFormatException {
        checkCantInPrivate(entityTypeMessages);
        String tag = TAG_INIT_SET;
        String msg = deleteTag(entityTypeMessages.getMsgGet().getMsg(), tag.substring(0, tag.length() - 2));
        if (!msg.contains(SPACE) || msg.split(SPACE)[1].equals(NONE) || !isNumeric(msg.split(SPACE)[1])) {
            throw new InitSetFormatException(entityTypeMessages);
        }
        String key = msg.split(SPACE)[0];
        String value = msg.split(SPACE)[1];
        if (INIT_LIST.containsKey(entityTypeMessages.getFromGroupString())) {
            HashMap<String, String> sort = sortHashMap(INIT_LIST.get(entityTypeMessages.getFromGroupString()));
            for (Map.Entry<String, String> mapEntry2 : sort.entrySet()) {
                Matcher matcher = getName.matcher(mapEntry2.getKey());
                if (matcher.find() && matcher.group(1).toLowerCase().equals(key)) {
                    INIT_LIST.get(entityTypeMessages.getFromGroupString()).remove(mapEntry2.getKey());
                }
            }
        }

        if (INIT_LIST.containsKey(entityTypeMessages.getFromGroupString())) {
            INIT_LIST.get(entityTypeMessages.getFromGroupString()).put(makeNickToSender(key) + "由" + entityTypeMessages.getFromQq() + "指定\t", value);
        } else {
            HashMap<String, String> riList = new HashMap<>(30);
            riList.put(makeNickToSender(key) + "由" + entityTypeMessages.getFromQq() + "指定\t", value);
            INIT_LIST.put(entityTypeMessages.getFromGroupString(), riList);
        }

        sender(entityTypeMessages, stringFormatById(entitySystemProperties.getInitSet(entityTypeMessages.getFromGroupString()), makeNickToSender(key), value));
    }

    /**
     * 清空先攻列表
     */
    public void clr() throws CantInPrivateException {
        checkCantInPrivate(entityTypeMessages);
        INIT_LIST.remove(entityTypeMessages.getFromGroupString());
        sender(entityTypeMessages, entitySystemProperties.getClrDndInit(entityTypeMessages.getFromGroupString()));
    }

    private Map<String, String> putInitList(String nick, Map<String, String> initList, Matcher mMsgBefore, String msgBefore, int result) {
        if (!"".equals(msgBefore) && (msgBefore.charAt(0) == '+' || msgBefore.charAt(0) == '-')) {
            msgBefore = msgBefore.substring(1);
        }
        String tagD20 = ": " + msgBefore;
        initList.put(nick, tagD20 + "\t" + result);
        return initList;
    }
}
